home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Users Group Library 1996 July
/
C-C++ Users Group Library July 1996.iso
/
listings
/
v_10_12
/
1012063a
< prev
next >
Wrap
Text File
|
1992-10-11
|
16KB
|
726 lines
/*
* mpu.c
* device driver for mpu-401 midi card
*/
#include "../h/param.h"
#include "../h/types.h"
#include "../h/dir.h"
#include "../h/signal.h"
#include "../h/page.h"
#include "../h/seg.h"
#include "../h/user.h"
#include "../h/file.h"
#include "../h/tty.h"
#include "../h/systm.h"
#include "../h/conf.h"
#include "../h/errno.h"
#include "mpu.h"
/* external support prototypes */
int inb(int);
void outb(int, int);
caddr_t cvttoaddr(faddr_t);
int fubyte(faddr_t);
void subyte(char *, int);
int copyin(faddr_t, char *, int);
void printcfg(char *, int, int, int, int, char *, ...);
void printf(char *, ...);
int getchar(void);
void putchar(int);
int sleep(caddr_t, int);
void wakeup(caddr_t);
int timeout(int (*)(), caddr_t, int);
void untimeout(int);
int spl6(void);
void splx(int);
int cpass(void);
int passc(int);
int getc(struct clist *);
int putc(int, struct clist *);
#define DRIVERID 0x00 /* driver version */
/* I/O addresses and vector */
/* if using IRQ 2, set VECTOR to 25 (030+VECTOR-1) */
#define VECTOR 25
#define BASE 0x220 /* I/O address of mpu card */
#define CMD (BASE+1) /* command output port */
#define STATUS (BASE+1) /* mpu status port */
#define DATA BASE /* data input port */
/* Status flags (neg logic) */
#define RR_F 0x40 /* mpu ready to receive */
#define DA_F 0x80 /* data available flag */
/* Test RR and DA flags */
#define RR() (!(INB(STATUS)&RR_F))
#define rr() (!(inb(STATUS)&RR_F))
#define DA() (!(INB(STATUS)&DA_F))
#define da() (!(inb(STATUS)&DA_F))
/* Device interrupt level */
#define SPLINT spl6
/* Busy-wait looping count */
#define SPIN 100000
#define ACK 0xFE /* mpu command acknowledge */
#define YES 1
#define NO 0
#define E_OK 0 /* ok return code */
#define E_TIMEOUT 1 /* timeout return code */
#define E_INTR 2 /* interrupt return code */
#define PRI (PZERO+1) /* sleep/wakeup priority */
static struct clist in_q; /* input queue */
static int busy = NO; /* driver busy flag */
static int exist = NO; /* mpu card found flag */
static int isopen = NO; /* exclusive use flag */
static int debug = 0; /* debugging level */
static int waitda = 0; /* result DA timer */
/* local prototypes */
static int reset(void);
static int waitRR(void);
static int mpucmd(int);
static int mpuinb(int);
static void mpuoutb(int, int);
#define OUTB(addr,byte) mpuoutb((addr),(byte))
#define INB(addr) mpuinb(addr)
/*-----------------------------------------------------
* mpuinit - determine if device exists at BASE address
*/
void mpuinit()
{
int i, ver = 0, rev = 0;
in_q.c_cc = 0; /* input q is empty */
/*
* see if it's there by trying to reset
*/
outb(CMD, MPU_RESET);
for (i = 0; i < SPIN; ++i)
if (da())
break;
if (i == SPIN) {
outb(CMD, MPU_RESET);
for (i = 0; i < SPIN; ++i)
if (da())
break;
if (i == SPIN)
goto NOTFOUND;
}
if (inb(DATA) != ACK)
goto NOTFOUND;
/*
* get firmware version
*/
for (i = 0; i < SPIN; ++i) /* wait for RR */
if (rr())
break;
if (i == SPIN) /* timed out */
goto NOTFOUND;
outb(CMD, MPU_VERSION); /* send request */
for (i = 0; i < SPIN; ++i) /* wait for ack */
if (da() && inb(DATA) == ACK)
break;
if (i == SPIN) /* timed out */
goto NOTFOUND;
for (i = 0; i < SPIN; ++i) /* wait for data */
if (da()) {
ver = inb(DATA); /* read version */
break;
}
if (i == SPIN) /* timed out */
goto NOTFOUND;
/*
* get firmware revision
*/
for (i = 0; i < SPIN; ++i) /* wait for RR */
if (rr())
break;
if (i == SPIN) /* timed out */
goto NOTFOUND;
outb(CMD, MPU_REVISION); /* send request */
for (i = 0; i < SPIN; ++i) /* wait for ACK */
if (da() && inb(DATA) == ACK)
break;
if (i == SPIN) /* timed out */
goto NOTFOUND;
for (i = 0; i < SPIN; ++i) /* wait for data */
if (da()) {
rev = inb(DATA); /* read revision */
break;
}
printcfg("mpu", BASE, 1, VECTOR, -1,
"ver=%d rev=%d did=%d", ver, rev, DRIVERID);
exist = YES;
return;
NOTFOUND:
printf("MPU not found at %x\n", BASE);
}
/*-----------------------------------------------------
* mpuopen - check device availability and
* ensure exclusive access
*/
void mpuopen(dev, flag, id)
int dev, flag, id;
{
if (debug)
printf("open: dev=%x flag=%x id=%x\n", dev, flag,
id);
if (!exist) {
u.u_error = ENXIO;
if (debug)
printf("open: device doesn't exist\n");
return;
}
if (isopen) {
u.u_error = EBUSY;
if (debug)
printf("open: failed EBUSY\n");
return;
}
isopen = YES;
if (reset() != E_OK) {
u.u_error = EIO;
if (debug)
printf("open: failed can't reset mpu\n");
isopen = NO;
}
}
/*-----------------------------------------------------
* mpuclose - reset mpu and give up exclusive access
*/
void mpuclose(dev, flag)
int dev, flag;
{
if (debug)
printf("close: dev=%x flag=%x\n", dev, flag);
(void) reset();
while (getc(&in_q) != -1) /* eat in_q */
;
busy = isopen = NO;
}
/*-----------------------------------------------------
* mpuread - read data from mpu
*/
void mpuread(dev)
int dev;
{
int byte, oldpri;
if (debug)
printf("read: dev=%x u.u_count=%d\n", dev,
u.u_count);
/* wait till it's ok to enter */
while (busy)
sleep((caddr_t) &busy, PRI);
busy = YES;
/* first get bytes from input q */
while (u.u_count) {
byte = getc(&in_q);
if (byte == -1)
break; /* used up input q */
if (passc(byte) == -1) {
busy = NO;
wakeup((caddr_t) &busy);
return; /* satisfied request */
}
}
/* now get straight from device */
while (u.u_count) {
oldpri = SPLINT();
while (!DA())
if (sleep((caddr_t) mpuread, PRI|PCATCH) != 0) {
splx(oldpri);
u.u_error = EINTR;
if (debug)
printf("read: caught software interrupt\n");
busy = NO;
wakeup((caddr_t) &busy);
return;
}
splx(oldpri);
if (passc(INB(DATA)) == -1)
break; /* satisfied request */
}
busy = NO;
wakeup((caddr_t) &busy);
}
/*-----------------------------------------------------
* mpuwrite - write data to mpu
*/
void mpuwrite(dev)
int dev;
{
int ret;
if (debug)
printf("write: dev=%x u.u_count=%d\n", dev,
u.u_count);
/* wait till it's ok to enter */
while (busy)
sleep((caddr_t) &busy, PRI);
busy = YES;
while (u.u_count) {
ret = waitRR();
if (ret == E_TIMEOUT) {
if (debug)
printf("write: waitRR timed out\n");
u.u_error = EIO;
break;
} else if (ret == E_INTR) {
if (debug)
printf("write: waitRR caught software int\n");
u.u_error = EINTR;
break;
} else
OUTB(DATA, cpass());
}
busy = NO;
wakeup((caddr_t) &busy);
}
/*-----------------------------------------------------
* mpuioctl
*/
void mpuioctl(dev, cmd, arg, mode)
int dev, cmd;
faddr_t arg;
int mode;
{
struct mpustuff m;
int byte, ret, got_intr = NO, oldpri, timeouts;
if (debug)
printf("ioctl: dev=%x cmd=%x mode=%x ", dev, cmd,
mode);
/* convert ptr on 286 callers */
if (!IS386())
arg = (faddr_t) cvttoaddr(arg);
/* make local copy of mpustuff in m */
if (copyin(arg, (char *) &m, sizeof(struct mpustuff))
== -1) {
u.u_error = EFAULT;
if (debug)
printf("\nioctl: copyin error EFAULT\n");
return;
}
if (!IS386()) {
m.opbuf = (char *) cvttoaddr(m.opbuf);
m.resbuf = (char *) cvttoaddr(m.resbuf);
}
if (debug)
print